package com.zrkizzy.module.content.service.tag;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.zrkizzy.common.core.domain.response.OptionsVO;
import com.zrkizzy.common.core.utils.IdUtil;
import com.zrkizzy.common.core.utils.bean.BeanCopyUtil;
import com.zrkizzy.common.models.domain.blog.tag.BlogTags;
import com.zrkizzy.common.models.dto.blog.tag.BlogTagsDTO;
import com.zrkizzy.common.models.query.blog.tag.BlogTagsQuery;
import com.zrkizzy.common.redis.service.IRedisService;
import com.zrkizzy.content.facade.service.tag.IBlogTagsService;
import com.zrkizzy.module.content.constant.DefaultValueConst;
import com.zrkizzy.module.content.exception.BlogErrorCode;
import com.zrkizzy.module.content.mapper.tag.BlogTagsMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.List;

import static com.zrkizzy.common.redis.enums.RedisKey.OPTIONS_TAGS_KEY;

/**
 * <p>
 * 博客标签业务逻辑接口实现类
 * </p>
 *
 * @author zhangrongkang
 * @since 2023/9/5
 */
@Service
@Slf4j
public class BlogTagsServiceImpl implements IBlogTagsService {

    @Autowired
    private IdUtil idUtil;

    @Autowired
    private IRedisService redisService;

    @Autowired
    private BlogTagsMapper blogTagsMapper;

    /**
     * 获取所有博客标签
     *
     * @param blogTagsQuery 博客标签查询对象
     * @return 博客标签分页数据
     */
    @Override
    public Page<BlogTags> listBlogTags(BlogTagsQuery blogTagsQuery) {
        // 开启分页
        Page<BlogTags> page = new Page<>(blogTagsQuery.getCurrentPage(), blogTagsQuery.getPageSize());
        // 查询分页
        return blogTagsMapper.listBlogTags(page, blogTagsQuery);
    }

    /**
     * 添加或更新博客标签
     *
     * @param blogTagsDTO 博客标签数据接收对象
     * @return 是否添加/更新成功
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean saveBlogTags(BlogTagsDTO blogTagsDTO) {
        log.info("--------------------- 开始进行新增-更新操作 ---------------------");
        log.info("blogTagsDTO: {}", blogTagsDTO);
        // 根据标签名称查询标签对象
        BlogTags blogTags = getBlogTagsByName(blogTagsDTO.getName());
        // 清除Redis中的标签列表数据
        redisService.del(OPTIONS_TAGS_KEY.getKey());
        // 根据是否包含ID来判断添加-更新操作
        if (null != blogTagsDTO.getId()) {
            // 校验是否有同名标签
            checkForDuplicateName(blogTagsDTO.getId(), blogTags);
            // 更新博客标签
            return updateBlogTags(blogTagsDTO);
        }
        // 校验是否有同名标签
        checkForDuplicateName(null, blogTags);
        // 添加博客标签
        return insertBlogTags(blogTagsDTO);
    }

    /**
     * 获取指定博客标签信息
     *
     * @param blogTagsId 博客标签ID
     * @return 博客标签数据返回对象
     */
    @Override
    public BlogTags getBlogTagsById(Long blogTagsId) {
        return blogTagsMapper.selectById(blogTagsId);
    }

    /**
     * 根据博客标签名称获取指定博客标签
     *
     * @param name 博客标签名称
     * @return 博客标签对象
     */
    @Override
    public BlogTags getBlogTagsByName(String name) {
        // 定义查询对象
        QueryWrapper<BlogTags> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("name", name);
        // 返回查询结果
        return blogTagsMapper.selectOne(queryWrapper);
    }

    /**
     * 批量删除博客标签数据
     *
     * @param ids 博客标签ID
     * @return true：删除成功，false：删除失败
     */
    @Override
    public Boolean deleteBatch(List<Long> ids) {
        // 清除Redis中的标签列表数据
        redisService.del(OPTIONS_TAGS_KEY.getKey());
        // 删除数据库中的数据
        return blogTagsMapper.deleteBatchIds(ids) == ids.size();
    }

    /**
     * 获取所有博客标签选项
     *
     * @return 所有博客标签集合
     */
    @Override
    public List<OptionsVO> listOptions() {
        // 先判断Redis
        if (redisService.hasKey(OPTIONS_TAGS_KEY.getKey())) {
            // 存在则直接返回
            return redisService.getList(OPTIONS_TAGS_KEY.getKey(), OptionsVO.class);
        }
        // 不存在则获取标签选项集合
        List<OptionsVO> tagsList = blogTagsMapper.listOptions();
        // 不为空则存储文章标签到Redis
        if (!CollectionUtils.isEmpty(tagsList)) {
            // 存储Redis，时间为不过期当更新标签时再清空
            redisService.setList(OPTIONS_TAGS_KEY.getKey(), tagsList);
        }
        return tagsList;
    }

    /**
     * 更新当前博客标签
     *
     * @param blogTagsDTO 博客标签数据接收对象
     * @return 是否更新成功
     */
    private Boolean updateBlogTags(BlogTagsDTO blogTagsDTO) {
        log.info("--------------------- 执行更新操作 ---------------------");
        // 对博客标签进行更新操作并返回响应结果
        return blogTagsMapper.updateById(BeanCopyUtil.copy(blogTagsDTO, BlogTags.class)) == 1;
    }
    
    /**
     * 添加新的博客标签
     *
     * @param blogTagsDTO 博客标签数据接收对象
     * @return 是否添加成功
     */
    private Boolean insertBlogTags(BlogTagsDTO blogTagsDTO) {
        log.info("--------------------- 开始进行新增操作 ---------------------");
        // 生成博客标签ID
        Long id = idUtil.nextId();
        // 设置ID
        blogTagsDTO.setId(id);
        // 默认文章数量
        blogTagsDTO.setCount(DefaultValueConst.DEFAULT_ARTICLE_COUNT);
        // 添加博客标签数据并返回添加结果
        return blogTagsMapper.insert(BeanCopyUtil.copy(blogTagsDTO, BlogTags.class)) == 1;
    }

    /**
     * 校验是否存在重名博客标签
     *
     * @param tagsId 博客标签ID
     * @param blogTags 根据传来参数查询出的博客标签对象
     */
    private void checkForDuplicateName(Long tagsId, BlogTags blogTags) {
        // 定义校验异常
        if (blogTags != null && (tagsId == null || !tagsId.equals(blogTags.getId()))) {
            throw BlogErrorCode.TAGS_NAME_EXIST.exception();
        }
    }

}
